<!DOCTYPE HTML>
<html>
<head>
<title>Run / RunWait | AutoHotkey</title>
<meta name="description" content="The Run and RunWait commands run an external program. RunWait will wait until the program finishes before continuing." />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
<script type="text/javascript">$(function(){0<=window.navigator.userAgent.toLowerCase().indexOf("ucbrowser")&&CaoNiMaDeUc()})</script>
<style type="text/css">
.style3 {color: #FF0000; font-weight: bold; }
</style>
</head>
<body>

<h1>Run / RunWait</h1>

<p>运行外部程序. 与 Run 不同, RunWait 会等待程序结束才继续往后执行.</p>

<pre class="Syntax">
<span class="func">Run</span>, Target <span class="optional">, WorkingDir, Options, OutputVarPID</span>
<span class="func">RunWait</span>, Target <span class="optional">, WorkingDir, Options, OutputVarPID</span>
</pre>
<h2 id="Parameters">参数</h2>
<dl>

  <dt>Target</dt>
  <dd><p>要运行的文档, URL, 可执行文件(.exe, .com, .bat, 等等), 快捷方式(.lnk) 或<a href="#verbs">系统动词</a>(请参阅备注). 如果 <em>Target</em> 是本地文件且指定时没有包含路径, 则首先搜索 <a href="../Variables.htm#WorkingDir">A_WorkingDir</a>. 如果那里没有找到匹配的文件, 如果它集成在系统中("已知的"), 则系统会搜索并运行此文件, 例如包含在 PATH 环境变量的其中某个文件夹中.</p>
      <p>要传递参数, 请让它们紧跟在程序或文档名的后面. 如果参数包含空格, 则把它们括在双引号中是最可靠的(虽然它在某些情况下没有括在双引号中也能工作).</p></dd>

  <dt>WorkingDir</dt>
  <dd><p>用于运行项目的工作目录. 即使它包含空格, 也不要括在双引号中. 如果省略, 则使用脚本自己的工作目录(<a href="../Variables.htm#WorkingDir">A_WorkingDir</a>).</p></dd>

  <dt>Options</dt>
  <dd><p>如果省略, 命令正常运行 <em>Target</em>, 并且当 <em>Target</em> 不能启动时显示警告对话框. 要更改此行为, 请指定以下一个或多个单词:</p>
      <p><strong>Max</strong>: 最大化运行</p>
      <p><strong>Min</strong>: 最小化运行</p>
      <p><strong>Hide</strong>: 隐藏运行(不能和上面任意一个选项组合使用)</p>
      <p class="note"><strong>注意</strong>: 一些程序(例如 Calc.exe) 不会遵循请求的启动状态, 因此对于它们 Max/Min/Hide 没有效果.</p>
      <p id="UseErrorLevel"><strong>UseErrorLevel</strong>: 可以单独指定 UseErrorLevel 或和上面的其中一个单词组合使用(把它和其他单词用空格分隔). 如果运行失败, 则使用此选项会跳过警告对话框, 设置 <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 为单词 ERROR, 并让<a href="../misc/Threads.htm">当前线程</a>继续执行. 如果运行成功, 则 RunWait 会把 <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 设置为程序的退出代码, 而 Run 把它设置为 0.</p>
      <p id="LastError">指定 UseErrorLevel 时, 变量 <strong>A_LastError</strong> 被设置为操作系统 GetLastError() 函数返回的结果. A_LastError 是一个介于 0 和 4294967295 之间的数字(总是为十进制而非十六进制). 零(0) 意味着成功, 但其他任何数字意味着运行失败. 每个数字对应一种特定的错误状态(要获取整个列表, 请在 <a href="https://www.microsoft.com">www.microsoft.com</a> 中搜索 "system error codes"). 像 <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 一样, A_LastError 是与每个线程关联的设置, 即由其他<a href="../misc/Threads.htm">线程</a>产生的中断不会改变它. 然而, A_LastError 还可由 <a href="DllCall.htm#LastError">DllCall()</a> 设置.</p></dd>

  <dt>OutputVarPID</dt>
  <dd><p>变量名, 用来存储新运行程序的唯一<a href="Process.htm">进程 ID(PID)</a>. 如果无法确定则 PID 被设置为空, 这经常发生在运行系统动词, 文档或快捷方式而不是直接的可执行文件时. RunWait 也支持此参数, 不过它获取的 <em>OutputVarPID</em> 必须在<a href="../misc/Threads.htm">另一个线程</a>中进行检查(否则, 这个 PID 将是无效的, 因为 RunWait 后的代码执行时相应的进程已经终止了).</p>
      <p>在 Run 命令获取 PID, 此进程要创建的窗口可能还不存在. 要等待它至少创建一个窗口, 请使用 <code><a href="WinWait.htm">WinWait</a> ahk_pid %OutputVarPID%</code>.</p></dd>

</dl>
<h2 id="Error_Handling">错误处理</h2>
<p><span class="ver">[v1.1.04+]</span>: 此命令失败时会抛出异常. 想了解更多信息, 请参阅<a href="Catch.htm#RuntimeErrors">运行时错误</a>.</p>
<p>Run: 只有在使用了 UseErrorLevel 时才会设置 <a href="../misc/ErrorLevel.htm">ErrorLevel</a>, 在这种情况下失败时 ErrorLevel 被设置为单词 ERROR 而成功时为 0.</p>
<p>RunWait: 设置 ErrorLevel 为程序的退出代码(32 位的有符号整数). 如果使用了 UseErrorLevel 且运行失败, 则把它设置为单词 ERROR.</p>
<h2 id="Remarks">备注</h2>
<p>与 Run 不同, RunWait 会等待 <em>Target</em> 关闭或退出, 此时 <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 被设置为程序的退出代码(32 位的有符号整数). 一些程序即使它们仍在运行但看起来立即返回了; 这些程序启动了另外的进程.</p>
<p>如果 <em>Target</em> 包含逗号, 则必须对它们进行<a href="../misc/EscapeChar.htm">转义</a>, 如同下面例子中的三次演示:</p>
<pre>Run rundll32.exe shell32.dll<span class="style3">`,</span>Control_RunDLL desk.cpl<span class="style3">`,`,</span> 3  <em>; 打开控制面板 &gt; 显示属性 &gt; 设置</em></pre>
<p>通过 <a href="../Variables.htm#ComSpec">ComSpec</a>(cmd.exe) 运行程序时(也许由于您需要重定向程序的输入和输出), 如果可执行程序的路径或名称包含空格, 则整个字符串必须括在一对外部的引号中. 在下面的例子中, 外部引号显示为红色, 而内部所有的引号显示为黑色:</p>
<pre>Run %comSpec% /c <span class="style3">"</span>"C:\My Utility.exe" "param 1" "second param" &gt;"C:\My File.txt"<span class="style3">"</span></pre>
<p>如果无法启动<em>目标</em>, 将显示包含此错误信息的窗口, 并结束当前线程, 除非在第 3 个参数中指定字符串 <strong>UseErrorLevel</strong>, 或者使用 <a href="Try.htm">Try</a>/<a href="Catch.htm">Catch</a> 语句进行捕获.</p>
<p>当 <em>Target</em> 为准确路径时可轻微提升性能, 例如使用 <code>Run, C:\Windows\Notepad.exe "C:\My Documents\Test.txt"</code> 代替 <code>Run, C:\My Documents\Test.txt</code>.</p>
<p>Run 还可以打开特殊的 <a href="../misc/CLSID-List.htm">CLSID 文件夹</a>. 例如:</p>
<pre>Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}  <em>; 打开 "我的电脑" 文件夹.</em>
Run ::{645ff040-5081-101b-9f08-00aa002f954e}  <em>; 打开回收站.</em></pre>
<p id="verbs">系统动词对应于资源管理器中文件右键菜单的可用操作. 如果启动文件时没有指定动词, 则使用那种文件类型的默认动词(通常为 "打开"). 如果指定了, 则动词后应该跟着默认文件名. 目前支持下列动词:</p>
<table class="info">
  <tr>
    <th style="width:8%">动词</th>
    <th abbr="Descr">描述</th>
  </tr>
  <tr>
    <td>*<i>动词</i></td>
    <td><span class="ver">[AHK_L 57+]:</span> 任何系统定义或自定义的动词. 例如: <code>Run *Compile %A_ScriptFullPath%</code>. 在 Windows Vista 和更高版本中, 可以使用 <a href="#RunAs">*RunAs</a> 动词代替 <i>以管理员身份运行</i> 右键菜单.</td>
  </tr>
  <tr>
    <td>properties(属性)</td>
    <td>
      <p>显示指定文件的资源管理器属性窗口. 例如: <code>Run, properties "C:\My File.txt"</code></p>
      <p class="note"><strong>注意</strong>: 当脚本终止时属性窗口会自动关闭. 要避免这种情况, 请使用 <a href="WinWait.htm">WinWait</a> 等待窗口出现, 然后使用 <a href="WinWaitClose.htm">WinWaitClose</a> 等待用户关闭它.</p>
    </td>
  </tr>
  <tr>
    <td>find(查找)</td>
    <td>在指定的文件夹中打开资源管理器的搜索助理或查找文件窗口实例. 例如: <code>Run, find D:\</code></td>
  </tr>
  <tr>
    <td>explore(浏览)</td>
    <td>打开指定文件夹的资源管理器实例. 例如: <code>Run, explore %A_ProgramFiles%</code>.</td>
  </tr>
  <tr>
    <td>edit(编辑)</td>
    <td>打开指定的文件进行编辑. 如果指定的文件类型没有关联 "edit" 动作时, 它不起作用. 例如: <code>Run, edit "C:\My File.txt"</code></td>
  </tr>
  <tr>
    <td>open</td>
    <td>打开指定的文件(一般不需要, 因为这对于大多数文件类型是默认的动作). 例如: <code>Run, open "My File.txt"</code>.</td>
  </tr>
  <tr>
    <td>print</td>
    <td>使用关联的应用程序打印指定的文件, 如果有. 例如: <code>Run, print "My File.txt"</code></td>
  </tr>
</table>
<p>当 RunWait 处于等待状态时, 可以通过<a href="../Hotkeys.htm">热键</a>, <a href="Menu.htm">自定义菜单项</a>或<a href="SetTimer.htm">计时器</a>启动新的<a href="../misc/Threads.htm">线程</a>.</p>

<h2 id="RunAs">以管理员权限运行(或是启动)<span class="ver">[AHK_L 57+]:</span></h2>
<p>对于可执行文件, 命令 <em>*RunAs</em> 相当于右键菜单的 <em>以管理员权限运行</em> 命令. 例如, 以下代码尝试以管理员权限启动自身:</p>
<pre>full_command_line := DllCall("GetCommandLine", "str")

if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
    try
    {
        if A_IsCompiled
            Run *RunAs "%A_ScriptFullPath%" /restart
        else
            Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
    }
    ExitApp
}

MsgBox A_IsAdmin: %A_IsAdmin%`nCommand line: %full_command_line%</pre>
<p>如果用户取消了 UAC 对话框或者是其他原因启动失败, 脚本就会直接退出.</p>
<p>在使用了 <a href="../Scripts.htm#SlashR">/restart</a> 启动参数, 且启动新进程实例的语句在 ExitApp 之前的时候, 需要确保 <a href="_SingleInstance.htm">single instance(单一实例)</a> 提示弹窗没有关闭.</p>
<p>如果 UAC 禁止了, <em>*RunAs</em> 将不提权启动进程. 在命令行检查 <code>/restart</code> 以防脚本进入无限重启的循环之中. 注意 <code>/restart</code> 为内置开关, 所以它没有列入<a href="../Scripts.htm#cmd_args">命令行参数之中</a>.</p>
<p>可以修改该示例以适应脚本的需要:</p>
<ul>
  <li>如果脚本的确需要管理员权限, 检查一次 A_IsAdmin 以免 <em>*RunAs</em> 提权脚本失败(比如因为被 UAC 禁止了).</li>
  <li>为保持脚本运行, 即使用户取消了 UAC 提示, 移动 ExitApp 到 try 区块.</li>
  <li>为保持脚本运行, 即使重新启动失败(比如脚本文件已被重命名或删除), 移除 ExitApp 并且使用 RunWait 代替 Run. 若是成功, <code>/restart</code> 使新实例终止旧实例. 若是失败, 新实例的退出及 RunWait 返回.</li>
</ul>
<p><span class="ver">[v1.0.92.01+]:</span> 如果 UAC 开启, AutoHotkey 安装程序为 <em>.ahk</em> 文件注册 <em>RunAs</em> 动作, 这允许 <code>Run *RunAs script.ahk</code> 默认以管理员权限启动脚本.</p>

<h2 id="Related">相关</h2>
<p><a href="RunAs.htm">RunAs</a>, <a href="Process.htm">Process</a>, <a href="Exit.htm">Exit</a>, <a href="../misc/CLSID-List.htm">CLSID 列表</a>, <a href="DllCall.htm">DllCall()</a></p>

<h2 id="Examples">示例</h2>
<div class="ex" id="ExBasic">
<p><a class="ex_number" href="#ExBasic"></a> Run 能够从任何目录下启动 Windows 系统程序. 注意, 可执行文件的扩展名如 .exe 可以省略.</p>
<pre>Run, notepad</pre>
</div>

<div class="ex" id="ExURL">
<p><a class="ex_number" href="#ExURL"></a> Run 能够启动 URLs:</p>
<p>以下是在用户的默认网页浏览器中打开一个互联网地址.</p>
<pre>Run, https://www.google.com</pre>
<p>以下打开默认的电子邮件应用程序并填写收件人.</p>
<pre>Run, mailto:someone@somedomain.com</pre>
<p>下面的操作和上面一样, 加上主题和正文.</p>
<pre>Run, mailto:someone@somedomain.com?subject=This is the subject line&amp;body=This is the message body's text.</pre>
</div>

<div class="ex" id="ExErrorLevel">
<p><a class="ex_number" href="#ExErrorLevel"></a> 在最大化应用程序中打开文档, 并在失败时显示一个自定义的错误信息.</p>
<pre>Run, ReadMe.doc, , Max UseErrorLevel
if (ErrorLevel = "ERROR")
    MsgBox The document could not be launched.</pre>
</div>

<div class="ex" id="ExVerb">
<p><a class="ex_number" href="#ExVerb"></a> 在最小化状态下运行 dir 命令, 并将输出结果存储在文本文件中. 之后, 文本文件及其属性对话框将被打开.</p>
<pre>#Persistent
RunWait, %ComSpec% /c dir C:\ &gt;&gt;C:\DirTest.txt, , Min
Run, C:\DirTest.txt
Run, properties C:\DirTest.txt</pre>
</div>

<div class="ex" id="ExCLSID">
<p><a class="ex_number" href="#ExCLSID"></a> Run 能够启动 <a href="../misc/CLSID-List.htm">CLSID</a>:</p>
<p>下面打开回收站.</p>
<pre>Run, ::{645ff040-5081-101b-9f08-00aa002f954e}</pre>
<p>下面打开 "我的电脑" 目录.</p>
<pre>Run, ::{20d04fe0-3aea-1069-a2d8-08002b30309d}</pre>
</div>

<div class="ex" id="ExMultipleCmds">
<p><a class="ex_number" href="#ExMultipleCmds"></a> 要连续运行多个命令, 请每个命令之间使用 "&amp;&amp;".</p>
<pre>Run, %ComSpec% /c dir /b &gt; C:\list.txt &amp;&amp; type C:\list.txt &amp;&amp; pause</pre>
</div>

<div class="ex" id="StdOut">
<p><a class="ex_number" href="#StdOut"></a> 以下函数可以用来运行一个命令并检索其输出, 或者一次性运行多个命令并检索其输出.</p>
<pre>MsgBox % RunWaitOne("dir " A_ScriptDir)

<em>; ...或一次执行多条命令并获取其输出:</em>
MsgBox % RunWaitMany("
(
echo 在这填入命令,
echo 会执行所有命令,
echo 并获取输出.
)")

RunWaitOne(command) {
    <em>; WshShell 对象: <a href="http://msdn.microsoft.com/en-us/library/aew9yb99">http://msdn.microsoft.com/en-us/library/aew9yb99</a></em>
    shell := ComObjCreate("WScript.Shell")
    <em>; 通过 cmd.exe 执行单条命令</em>
    exec := shell.Exec(ComSpec " /C " command)
    <em>; 读取并返回命令的输出</em>
    return exec.StdOut.ReadAll()
}

RunWaitMany(commands) {
    shell := ComObjCreate("WScript.Shell")
    <em>; 打开 cmd.exe 禁用命令显示</em>
    exec := shell.Exec(ComSpec " /Q /K echo off")
    <em>; 发送并执行命令, 使用新行分隔</em>
    exec.StdIn.WriteLine(commands "`nexit")  <em>; 保证执行完毕后退出!</em>
    <em>; 读取并返回所有命令的输出</em>
    return exec.StdOut.ReadAll()
}
</pre>
</div>

<div class="ex" id="ExecScript">
<p><a class="ex_number" href="#ExecScript"></a> 在新的 AutoHotkey 进程中执行给定的代码.</p>
<pre>ExecScript(Script, Wait:=true)
{
    shell := ComObjCreate("WScript.Shell")
    exec := shell.Exec("AutoHotkey.exe /ErrorStdOut *")
    exec.StdIn.Write(script)
    exec.StdIn.Close()
    if Wait
        return exec.StdOut.ReadAll()
}

<em>; 示例:</em>
InputBox expr,, 输入一个表达式, 将用一个新的脚本来计算.,,,,,,, Asc("*")
result := ExecScript("FileAppend % (" expr "), *")
MsgBox % "Result: " result
</pre>
</div>

</body>
</html>